<template>
  <div class="ai-conversation-one-container">
    <div class="ai-conversation-one-message">
      <div v-if="resultArray.length" class="markdown-body">
        <div v-for="(item, index) in resultArray" :key="index">
          <div v-if="item.type === 'deepThink'" class="deep-think">
            <!-- 是否展示思考过程 -->
            <div v-if="showThink">
              <div class="deep-tink-tool" @click="toggleDeepThinking(item)">
                <p class="deep-toggle-text">
                  <span v-if="item.status === 'deep-thinking'">思考中</span>
                  <span v-else-if="item.status === 'deep-done'"> 已深度思考（用时 {{ item.seconds }} 秒） </span>
                  <span v-else-if="item.status === 'deep-stopped'"> 思考已停止 </span>
                </p>
                <div class="deep-toggle-btn el-icon-arrow-up" :class="item.visible ? 'arrow-up' : 'arrow-down'"></div>
              </div>
              <div v-if="item.visible" class="deep-content">
                {{ item.content }}
              </div>
            </div>
          </div>
          <el-tooltip v-else-if="item.type === 'button' && (serviceBtn || isRecords)" class="ai-stream-item" open-delay="500" :hide-delay="500">
            <template #content>
              <div class="ai-density-code">
                <h4>输入:</h4>
                <div class="ai-density-item" v-html="item.formattedInput"></div>
                <h4>输出:</h4>
                <div class="ai-density-item">{{ item.formattedOutput }}</div>
              </div>
            </template>
            <span class="ai-density-btn">
              {{ item.content }}
              <i class="ai-check el-icon-check" v-if="item.check"></i>
            </span>
          </el-tooltip>
          <div v-else-if="item !== ''" class="ai-stream-item" v-html="renderedContent(item)" />
          <div v-else>{{ thinkingText }}</div>
        </div>
      </div>
      <div v-else>{{ thinkingText }}</div>
    </div>
  </div>
</template>

<script>
import markdownit from "markdown-it/dist/markdown-it.min.js";
import markdownItHighlight from "markdown-it";
import "highlight.js/styles/default.css";
import he from "he";
// import { ArrowUp, Select } from '@epoint-fe/eui-icons';

const md = markdownit({
  html: true, // 允许在 Markdown 中使用 HTML 标签
}).use(markdownItHighlight); // 解析markdown并高亮代码

export default {
  props: {
    message: {
      type: Object,
      required: true,
    },
    stopAnswer: {
      type: Boolean,
      default: null,
    },
  },
  data() {
    return {
      isRecords: false,
      timer: null,
      reader: null,
      stopStatus: null,
      timeout: 15000, // 超时时间：15s
      resultArray: [],
      seconds: 0,
      startTime: null,
      endTime: null,
      isDeepThink: false,
      currentThinkingContent: "",
      thinkingText: "正在理解您的输入...", // 根据实际情况设置
      serviceBtn: true, // 根据实际情况设置
      showThink: true, //是否展示思考过程
    };
  },
  watch: {
    stopAnswer(newVal) {
      if (this.stopStatus === null) {
        this.stopStreamRequest();
      }
      this.stopStatus = newVal;
    },
  },
  methods: {
    startDeepThinkTimer() {
      this.startTime = Date.now();
      this.seconds = 0;
    },
    stopDeepThinkTimer() {
      if (this.startTime) {
        this.endTime = Date.now();
        this.seconds = Math.floor((this.endTime - this.startTime) / 1000);
      }
    },
    toggleDeepThinking(item) {
      item.visible = !item.visible;
    },
    decodeHtml(html) {
      return he.decode(html);
    },
    async getStream(url) {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), this.timeout);

      // 定义可能存在的思考标签数组
      const thinkTags = ["think", "baiduthink"]; // 可以根据需要扩展
      try {
        const response = await fetch(url, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          signal: controller.signal,
        });

        clearTimeout(timeoutId);
        this.reader = response.body.getReader();
        this.$emit("stream-complete", false);

        let responseData = "";
        while (true) {
          const { done, value } = await this.reader.read();
          if (done) {
            var historyParams = {
              //保存历史记录需要的参数
              askguid: this.message.askguid,
              historyContent: JSON.stringify({
                content: this.resultArray,
              }),
              messageType: "streamMessage",
              time: this.message.time,
              sessionid: this.message.sessionid,
            };
            clearInterval(this.timer);

            if (this.resultArray.length === 0) {
              this.resultArray.push({
                content: `<p class="ai-empty-msg">请求超时</p>`,
              });
            } else if (this.isDeepThink) {
              const lastThinkIndex = this.resultArray.findIndex((item) => item.type === "deepThink");
              if (lastThinkIndex !== -1) {
                this.resultArray[lastThinkIndex].status = "deep-stopped";
              }
              this.isDeepThink = false;
            }

            this.$emit("stream-complete", true, this.resultArray, historyParams);
            this.$emit("scroll-to-bottom");
            break;
          }

          responseData = new TextDecoder().decode(value);
          try {
            const jsonObjects = responseData.split("\n").filter(Boolean); //有可能一下返回多行
            jsonObjects.forEach((objStr) => {
              //objStr 代表接口返回的一行
              const parsedData = JSON.parse(objStr);

              let resultContent = "";
              if (typeof parsedData.result === "string" || typeof parsedData.result === "number") {
                try {
                  const resultJson = JSON.parse(parsedData.result);
                  if (resultJson.content) {
                    resultContent = resultJson.content;
                  } else {
                    resultContent = resultJson + "";
                  }
                } catch (e) {
                  // 如果 parsing 失败，保留原始字符串，前提是内容不为空
                  if (parsedData.result !== "") {
                    resultContent = parsedData.result;
                  }
                }
              } else if (typeof parsedData.result === "object" && parsedData.result.content) {
                // 确保 content 字段不为空
                if (parsedData.result.content !== "") {
                  resultContent = parsedData.result.content;
                }
              }
              // 如果 resultContent 为空，则直接返回，不输出内容
              if (resultContent == "") {
                //为实际 这一行里面 的输出内容
                return;
              }

              console.log("@@@resultContent@@@", resultContent);
              // 检查是否包含任何思考结束标签
              const matchedEndTag = thinkTags.find((tag) => resultContent.includes(`</${tag}>`));
              if (matchedEndTag) {
                this.isDeepThink = false;
                this.stopDeepThinkTimer();
                //处理 </think> 之前的文字内容
                const thinkEndIndex = resultContent.indexOf("</think>");
                if (thinkEndIndex > 0) {
                  // 如果存在非标签内容
                  const contentBeforeThinkEnd = resultContent.substring(0, thinkEndIndex).trim();
                  if (contentBeforeThinkEnd.length > 0) {
                    // 确保有实际内容需要追加
                    this.currentThinkingContent += contentBeforeThinkEnd;
                  }
                }
                const lastThinkIndex = this.resultArray.findIndex((item) => item.type === "deepThink");
                if (lastThinkIndex !== -1) {
                  this.resultArray[lastThinkIndex].status = "deep-done";
                  this.resultArray[lastThinkIndex].seconds = this.seconds;
                }
                return;
              }
              // 深度思考
              if (this.isDeepThink) {
                this.currentThinkingContent += resultContent;

                const lastThinkIndex = this.resultArray.findIndex((item) => item.type === "deepThink");
                if (lastThinkIndex !== -1) {
                  this.resultArray[lastThinkIndex].content = this.currentThinkingContent;
                }
                this.$emit("scroll-to-bottom");
                return;
              }
              // 检查是否包含任何思考标签
              const matchedTag = thinkTags.find((tag) => resultContent.includes(`<${tag}>`));
              if (matchedTag) {
                //百度的不展示思考过程
                if (matchedTag == "baiduthink") {
                  this.showThink = false;
                }
                this.isDeepThink = true;
                this.startDeepThinkTimer();
                //处理 <think> 之后的文字内容
                const thinkContentStart = resultContent.indexOf(">") + 1;
                const thinkContent = resultContent.substring(thinkContentStart).trim(); // 提取<think>之后的内容
                this.currentThinkingContent = thinkContent; // 将提取的内容作为初始思考内容
                this.resultArray.push({
                  content: this.currentThinkingContent,
                  type: "deepThink",
                  visible: true,
                  status: "deep-thinking",
                  seconds: 0,
                });
                this.$emit("scroll-to-bottom");
                return;
              }

              // 命中
              if (resultContent.indexOf("functioncall") !== -1) {
                try {
                  if (this.serviceBtn) {
                    const jsonObject = JSON.parse(resultContent);
                    if (jsonObject.paramval && typeof jsonObject.paramval === "string") {
                      jsonObject.paramval = JSON.parse(jsonObject.paramval);
                    }
                    this.resultArray.push({
                      type: "button",
                      content: jsonObject.functioncall,
                      formattedInput: md.render(`\`\`\`json\n${JSON.stringify(jsonObject.paramval, null, 2)}\n\`\`\``),
                      formattedOutput: "",
                      check: false,
                    });
                  }
                  this.$emit("scroll-to-bottom");
                  return;
                } catch (error) {
                  console.error("JSON格式错误:", error);
                }
              }
              if (resultContent.indexOf("functionguid") !== -1) {
                if (this.serviceBtn) {
                  const formattedOutput = JSON.parse(resultContent),
                    index = this.resultArray.length - 1;
                  if (formattedOutput) {
                    this.resultArray[index].formattedOutput = formattedOutput.value;
                    this.resultArray[index].check = true;
                    this.$emit("scroll-to-bottom");
                  }
                }
                return;
              }
              //下面是实际 要渲染出的 回答 markdown格式
              const item = {
                content: resultContent,
              };
              const lastIndex = this.resultArray.length - 1;
              if (lastIndex >= 0 && !this.resultArray[lastIndex]?.type) {
                this.resultArray[lastIndex].content += item.content;
              } else {
                this.resultArray.push(item);
              }
              this.$emit("scroll-to-bottom");
            });
          } catch (error) {
            console.error("解析数据时出错:", error);
            var errortext = "流式数据格式解析出错";
            this.resultArray.push({
              content: errortext,
            });
          }
        }
      } catch (error) {
        const errorText = error.name === "AbortError" ? `<p class="ai-empty-msg">请求超时</p>` : `<p class="ai-empty-msg">请求失败</p>`;

        this.resultArray.push({
          content: errorText,
        });
        this.$emit("stream-complete", true, this.resultArray);
        this.$emit("scroll-to-bottom");
      }
    },
    //替换url
    replaceOrigin(url) {
      const oldPrefix = "http://192.168.219.30:8080/epoint-blbb-web";
      const newPrefix = "https://zwblbb.epoint.com.cn:6443/epoint-blbb-web";

      if (url.startsWith(oldPrefix)) {
        const urlObj = new URL(url);
        urlObj.protocol = "https:";
        urlObj.hostname = "zwblbb.epoint.com.cn";
        urlObj.port = "6443";
        return urlObj.toString();
      }
      return url;
    },
    renderedContent(item) {
      const decodedContent = this.decodeHtml(item.content).replace(/\\n/g, "\n");
      const rendered = md.render(decodedContent);
      return rendered;
    },
    stopStreamRequest() {
      clearInterval(this.timer);
      this.reader && this.reader.cancel();
    },
    getCookie(name) {
      const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
      return match ? match[2] : "";
    },
    getContent() {
      return this.resultArray.map((item) => item.content).toString();
    },
  },
  mounted() {
    const messageContent = this.message.content?.content;
    const url = this.message.content?.url;
    if (messageContent) {
      if (!Array.isArray(messageContent)) {
        this.resultArray.push({
          content: messageContent,
        });
      } else if (messageContent.length > 0) {
        this.resultArray = messageContent;
      }
      this.isRecords = true;
      this.$emit("stream-complete", true);
      return false;
    }
    var newUrl = url; //本地测试
    newUrl = this.replaceOrigin(url); //正式
    this.getStream(newUrl);
  },
  beforeDestroy() {
    this.stopStreamRequest();
  },
};
</script>

<style scoped>
.ai-rich-content /deep/ img {
  max-width: 200px;
  max-height: 200px;
  border-radius: 5px;
  vertical-align: top;
  cursor: pointer;
}

.ai-density-info {
  display: flex;
  margin-top: 3px;
  margin-bottom: 3px;
}

.ai-density-btn {
  display: inline-block;
  vertical-align: top;
  padding: 2px 8px;
  border-radius: 25px;
  color: #959595;
  cursor: pointer;
  white-space: nowrap;
  margin: 3px 3px 3px 0;
  background-image: linear-gradient(103deg, #d7e1f39e 0%, #d3dff5 63%, #c6d8f79c 124%);
}

.ai-check {
  width: 14px;
  height: 14px;
  padding-top: 2px;
}

.ai-density-code {
  max-width: 300px;
}

.ai-density-code h4 {
  line-height: 24px;
  padding-bottom: 4px;
}

.ai-density-code /deep/ code {
  border-radius: 3px;
  background: #e6e6e6;
}

.ai-density-item {
  word-break: break-all;
  padding-bottom: 5px;
}

.ai-empty-msg {
  color: rgb(230, 90, 90);
}

.deep-think {
  font-size: 12px;
  padding-top: 3px;
  padding-bottom: 3px;
}

.deep-tink-tool {
  padding: 4px 6px;
  border-radius: 5px;
  background-color: rgb(247, 247, 247);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}

.deep-toggle-text {
  margin-right: 4px;
}

.deep-content {
  margin-top: 5px;
  padding-left: 13px;
  color: #8b8b8b;
}

.deep-toggle-btn.arrow-down {
  transform: rotate(-180deg);
}
</style>
